﻿using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Lrd.Template.Core.Infrastructure.EntityHistory;
using Lrd.Template.Core.Infrastructure.Extensions;

namespace Lrd.Template.Core.Infrastructure.Entity
{
    public abstract class DbContextBase : DbContext
    {
        private readonly IServiceProvider _serviceProvider = null;
        private readonly IEntityMappingConfigurationTypeFinder _entityMappingConfigurationTypeFinder = null;
        private readonly ILogger _logger;

        protected DbContextBase(DbContextOptions options, IEntityMappingConfigurationTypeFinder entityMappingConfigurationTypeFinder, IServiceProvider serviceProvider)
             : base(options)
        {
            _serviceProvider = serviceProvider;
            _entityMappingConfigurationTypeFinder = entityMappingConfigurationTypeFinder;
            _logger = serviceProvider?.GetLogger(GetType()); ;
        }




        public IUnitOfWork UnitOfWork { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            IEntityMappingConfiguration[] mappings = _entityMappingConfigurationTypeFinder.FindAll(true).Select(o => Activator.CreateInstance(o) as IEntityMappingConfiguration).ToArray();
            foreach (var item in mappings)
            {
                item.Map(modelBuilder);

            }


        }


        public void BeginTransaction()
        {
            if (UnitOfWork == null)
            {
                return;
            }
            UnitOfWork.BeginTransaction();
        }
        public async Task BeginTransactionAsync(CancellationToken cancellationToken)
        {
            if (UnitOfWork == null)
            {
                return;
            }

            await UnitOfWork.BeginTransactionAsync(cancellationToken);
        }


        public override int SaveChanges()
        {
            var auditEntityHelper = _serviceProvider.GetService<IAuditEntityHelper>();
            var auditEntityEntries = auditEntityHelper?.GetAuditEntityEntry(this.ChangeTracker.Entries().ToList());
            int count= base.SaveChanges();
            if (count > 0 && auditEntityEntries?.Count() > 0)
            {
                var mediator = _serviceProvider.GetService<IMediator>();

                 mediator?.Publish(new AuditEntityEntryNotification(auditEntityEntries.ToList())).GetAwaiter();
            }

            return count;
        }

        public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
  
            var auditEntityHelper = _serviceProvider.GetService<IAuditEntityHelper>();
            var auditEntityEntries = auditEntityHelper?.GetAuditEntityEntry(this.ChangeTracker.Entries().ToList());
            int count = await base.SaveChangesAsync(cancellationToken);


            if (count > 0 && auditEntityEntries?.Count() > 0)
            {
                var mediator = _serviceProvider.GetService<IMediator>();

               await mediator?.Publish(new AuditEntityEntryNotification(auditEntityEntries.ToList()));
            }
   

            return count;
        }

        public override void Dispose()
        {
            base.Dispose();
            UnitOfWork = null;
        }
    }
}
